<?php
require_once 'WKernel/Application.php';
require_once 'WKernel/Component.php';
//patch
if(!function_exists('http_response_code')) {
	function http_response_code ($code){
		$stauses = array( 
			200 => 'OK', 			
			404 => 'Not found',
			302 => 'Found',
			500 => 'Internal Server Error');
		header('HTTP/1.1 ' . $code . ' ' . $stauses[$code]);
	}
}
class WF_Component implements WK_Component {
	private $config;
	
	private $status = 200;	
	private $headers = array();	
	private $content;
	
	protected $content_type = 'text/html';
	protected $charset      = 'utf-8';
	
	private static $_INSTANCE;
	private static $COMNAME = 'WFrontend';
	
	private static $_depth = 0;
	private static $_depth_limit = 3;
	
	private function __construct($config){
		$this->config = $config;
		$this->content_type = self::nvl(@$this->config['content_type'], $this->content_type);
		$this->charset      = self::nvl(@$this->config['charset'], $this->charset);
		//TODO: set default fatal error page title and message
	}
	
	public static function getInstance($config){
		if(!self::$_INSTANCE)
			self::$_INSTANCE = new self ($config);
		return self::$_INSTANCE;
	}
	
	public function getCommand($name, $params = array()){
		
	}
	
	public function initResponse(){		
		ob_end_clean();
		ob_start();
		$this->setRespHeader('Content-Type', $this->content_type . ';charset=' . $this->charset);
		$this->headers = array();
		$this->content = '';
		$this->status  = 200;
	}
	
	public function setRespStatus($code){
		$this->status = $code;
	}
	
	public function setRespHeader($name, $value){
		$this->headers[$name] = $value;
	}
	
	public function setRespContent($content){
		$this->content = $content;
	}
	
	public function flushResponse(){
		$unhandled_output = ob_get_contents();
		ob_end_clean();
		
		http_response_code($this->status);
		
		foreach ($this->headers as $name => $value){
			header($name . ': ' . $value);
		}
		
		echo $this->content;
		
		if(!@$this->config['suppress_unhandled_output']) 
			echo $unhandled_output;
	}
	
	/**
	* Return name of the component
	* @return string
	*/
	public function getName(){
		return self::$COMNAME;
	}
	
	public function httpRedirect($url){
		$this->initResponse();
		$this->setRespStatus(302);
		$this->setRespHeader('Location', $url);
		$this->flushResponse();
		exit();
	} 
	
	public function pageNotFound(){
		$this->initResponse();		
		$this->setRespStatus(404);
		$this->setRespContent(self::getFileContent(@$this->config['page404']));
		$this->flushResponse();
		exit();
	}	
	
	public function fatalError($exception){
		$this->initResponse();
		$this->setRespStatus(500);
		
		$title = @$this->config['error_page_title'];
		$alt   = @$this->config['error_page_message'];
		$trace = '';
		$arr_trace = $exception->getTrace();
		$num = count($arr_trace);
		foreach($arr_trace as $i => $step) {
			$trace .= "\n<b>".'STEP '.($num - $i)."</b>\n";
			$trace .= self::toolArraySerialize($step);
		}
		
		$page  = '<html>';
		$page .= '<head>';
		$page .= '<title>' . $title . '</title>';
		$page .= '</head>';
		$page .= '<body>';
		$page .= '<h1>'.$title.'</h1>';
		$page .= ( self::$DEBUG_MODE		
					? '<b>'.$exception->getMessage().' ('.$exception->getCode().')</b>' . 
					  '<h4>Trace:</h4>' .
					  '<pre>' . $trace . '</pre>' 
					: '<h2>'  . $alt   . '</h2>' );
		$page .= '</body>';
		$page .= '</html>';
		
		$this->setRespContent($page);
		$this->flushResponse();
		exit();
	} 
	
	protected static function toolArraySerialize($array, $type = 'assoc', $indent = '', $name = 'array') {
		self::$_depth++;
		
		if(self::$_depth > self::$_depth_limit) {
			self::$_depth--;
			if(is_array($array)){
				$type = $indent . 'array' . "\n";
			}
			elseif(is_object($array)){
				$type = $indent . get_class($array) . "\n";
			}
			return $type;
		}
		
		$string = '';
		
		if (is_string ( $array ) || is_numeric ( $array )) {
			self::$_depth--;
			return  $indent . $array . "\n";
		}
		
		switch ($type) {
			case 'assoc' :
				foreach ( $array as $key => $value )
					if (! is_array ( $value ))
						$string .= $indent . $key . ': ' . @htmlspecialchars ( $value ) . "\n";
					else
						$string .= $indent . $key . ': ' . "\n" . self::toolArraySerialize ( $value, $type, $indent . "\t" );
				break;
			case 'xml' :
				$string .= $indent . '<' . $name . '>';
				foreach ( $array as $key => $value )
					if (! is_array ( $value ))
						$string .= $indent . "\t" . '<' . $key . '>' . @htmlspecialchars ( $value ) . '</' . $key . '>' . "\n";
					else
						$string .= "\n" . self::toolArraySerialize ( $value, $type, $indent . "\t" );
				$string .= $indent . '</' . $name . '>';
				break;
		}
		
		self::$_depth--;
		
		return $string;
	}
}
WK_App::registerComponent(WF_Component::getName(), 'WF_Component');